#include<stdio.h>
#include<pthread.h>
#include<unistd.h>

//当具有多名厨师和多位顾客时-------混乱
//当阻塞队列中存在多名顾客同时阻塞，在厨师做好饭唤醒的时候可能同时唤醒多名顾客来吃饭，这是不合理的---只做了一碗饭不可能多名顾客同时吃
//因此在每一次加锁之后要循环判断是否有饭  if ---> while
//但此时程序又出现问题，运行不动
//因为顾客和厨师阻塞在同一个pcb等待队列上，有可能第一位顾客发现没饭唤醒的不是厨师而是另一位顾客，导致程序流程卡死
//解决：让不同的角色等待在不同的pcb等待队列上，确保没饭时候唤醒的是厨师，有饭时候唤醒的是顾客


int counter=0;   //柜台上是否有饭，0-没有，1-有

//定义互斥锁与条件变量
pthread_mutex_t mutex;
pthread_cond_t cond_cus;
pthread_cond_t cond_cook;

void* Cook(void* arg)
{
  while(1){
    pthread_mutex_lock(&mutex);  //先加锁
    while(counter > 0){    //需要循环判断是否有饭
      //表示有饭，阻塞厨师
      pthread_cond_wait(&cond_cook,&mutex);
    }
    //没有饭，厨师要去做饭
    counter++;
    printf("饭好了，快来吃饭啦！--- %d\n",counter);
    pthread_cond_signal(&cond_cus);  //唤醒至少一个顾客来吃饭
    pthread_mutex_unlock(&mutex);   //解锁
  }
  return NULL;
}
void* Custom(void* arg)
{
  while(1){
    pthread_mutex_lock(&mutex);  //先加锁
    while(counter <= 0){
      //没有饭，阻塞顾客
      pthread_cond_wait(&cond_cus,&mutex);
    }
     //有饭，顾客吃饭
    counter--;
    printf("饭真好吃，再来一碗吧！---- %d\n",counter);
    pthread_cond_signal(&cond_cook);   //唤醒至少一个厨师来做饭
    pthread_mutex_unlock(&mutex);
  }
  return NULL;
}
int main()
{
  //初始化互斥锁，条件变量
  pthread_mutex_init(&mutex,NULL);
  pthread_cond_init(&cond_cook,NULL);
  pthread_cond_init(&cond_cus,NULL);

  //首先创建两个线程--厨师、顾客
  pthread_t cook_tid[4],cus_tid[4];
  int ret;
  int i=0;
  for(i=0;i<4;++i){
    ret=pthread_create(&cook_tid[i],NULL,Cook,NULL);
    if(ret!=0){
      perror("pthread_create error!\n");
      return -1;
    }
    ret=pthread_create(&cus_tid[i],NULL,Custom,NULL);
    if(ret!=0){
      perror("pthread_create error!\n");
      return -1;
    }
  }
  

  //线程等待
  for(i=0;i<4;++i){
    pthread_join(cook_tid[i],NULL);
    pthread_join(cus_tid[i],NULL);
  }
  //互斥锁、条件变量的销毁
  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&cond_cus);
  pthread_cond_destroy(&cond_cook);
  return 0;
}
